"use strict";

/**获取当前运行的linux、windows操作系统已连接识别的磁盘存储设备
 * @description linux发行版操作系统是通过调用 lsblk 程序获取已识别连接的磁盘存储设备，解析并处理成数组包含对象的数据
 * @description windows操作系统是通过 child_process 模块通过 cscript.exe 程序调用 Visual Basic Script 代码脚本文件获得已识别连接的磁盘存储设备，解析并处理成数组包含对象的数据
 * @description 调用此函数之前，先确认linux发行版操作系统是否已安装 lsblk 程序，windows操作系统必须确认 cscript.exe 程序是否可正常调用。
 * @return Array
 * */
function getAllStorageDevice() {
    var child_process = require("child_process");
    var fs = require("fs");
    var ps = require("path");
    var node_process = require("process");
    var os = require("os");
    var StorageDeviceList = [];

    const win32_disk_letter = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];

    function deepCopy(InstanceSource) {
        try {
            let Origin1 = JSON.stringify(InstanceSource);
            let Origin2 = JSON.parse(Origin1);
            return Origin2;
        } catch (e) {
            return InstanceSource;
        }
    }

    function EraseMatchArrayItems(sourceArray, needEraseItem, notModifySourceArray) {
        if (typeof notModifySourceArray !== "boolean") {
            notModifySourceArray = false;
        }
        if (Object.prototype.toString.call(sourceArray) !== "[object Array]") {
            throw new Error("sourceArray Argument must be an array");
        }

        if (needEraseItem !== undefined) {
            var final = [];
            var found = false;
            while (true) {
                found = false;
                var funcResult = undefined;
                sourceArray.forEach(function (value, index, array) {
                    switch (typeof needEraseItem) {
                        case "function":
                            if (Object.prototype.toString.call(needEraseItem) === "[object Function]") {
                                funcResult = needEraseItem(value);
                                if (funcResult !== undefined) {
                                    if (typeof funcResult === "boolean") {
                                        if (funcResult) {
                                            found = true;
                                            if (!notModifySourceArray) {
                                                array.splice(index, 1);
                                            }
                                        } else {
                                            if (notModifySourceArray) {
                                                final.push(deepCopy(value));
                                            }
                                        }
                                    }
                                }
                            } else {
                                throw new Error("is Only Support Not Async Functions!");
                            }
                            break;
                        case "string":
                            if (String(needEraseItem).toString() === String(value).toString()) {
                                found = true;
                                if (!notModifySourceArray) {
                                    array.splice(index, 1);
                                }
                            } else {
                                if (notModifySourceArray) {
                                    final.push(deepCopy(value));
                                }
                            }
                            break;
                        case "number":
                            if (Number(needEraseItem).valueOf() === Number(value).valueOf()) {
                                found = true;
                                if (!notModifySourceArray) {
                                    array.splice(index, 1);
                                }
                            } else {
                                if (notModifySourceArray) {
                                    final.push(deepCopy(value));
                                }
                            }
                            break;
                        default:
                            throw new Error("needEraseItem is Only Support String Or Number Or Functions");
                    }
                });
                if (!found) {
                    if (notModifySourceArray) {
                        return final;
                    } else {
                        return undefined;
                    }
                }
            }
        } else {
            throw new Error("not Exist need Match Item");
        }
    }

    function size_comp(c1, c2) {
        var results;
        if (c1 === c2) {
            return true;
        } else {

            function reduces(a, b) {
                var baseNumber = 1;
                var count = 0;
                while (true) {
                    if (baseNumber > 16384) {
                        break;
                    }
                    baseNumber = baseNumber + baseNumber;
                    if ((a - baseNumber) === b) {
                        return true;
                    }
                    count++;
                }
                return false;
            }

            if (c1 > c2) {
                results = reduces(c1, c2);
            } else {
                results = reduces(c2, c1);
            }
            return results;
        }
    }

    function m_info() {
        return {
            name: "",
            type: "",
            model: "",
            path: "",
            index: 0,
            interfaces: "",
            read_only: false,
            removable_disk: false,
            partition: [],
            size: 0,
            system: false,
            serial_Number: "",
            mount: "",
            virtual: false,
            solid: false
        };
    }

    function s_info() {
        return {
            path: "",
            size: 0,
            free: 0,
            index: 0,
            read_only: false,
            removable_disk: false,
            primary: false,
            name: "",
            fileSystem: "",
            volumeName: "",
            volumeSerial: "",
            type: "",
            system: false,
            virtual: false,
            mount: ""
        }
    }

    switch (node_process.platform) {
        case "linux":
            try {
                var linux_StorageDevice1 = JSON.parse(child_process.execSync("lsblk -J -O -b").toString("utf8"));
                linux_StorageDevice1.blockdevices.forEach(function (v1, i1, a1) {
                    var m_body = m_info();
                    m_body.type = deepCopy(v1.type);
                    m_body.size = deepCopy(v1.size);
                    m_body.read_only = deepCopy(v1.ro);
                    m_body.name = deepCopy(v1.name);
                    m_body.removable_disk = deepCopy(v1.rm);
                    m_body.path = deepCopy(v1.path);
                    m_body.model = deepCopy(v1.model);
                    m_body.interfaces = deepCopy(v1.tran);
                    m_body.serial_Number = deepCopy(v1.serial);
                    if (String(v1.name).toLowerCase().indexOf("loop") >= 0) {
                        m_body.virtual = true;
                    } else {
                        m_body.virtual = false;
                        if (v1.rota) {
                            m_body.solid = false;
                        } else {
                            m_body.solid = true;
                        }
                    }
                    if (v1.children) {
                        v1.children.forEach(function (v2, i2, a2) {
                            var s_body = s_info();
                            if (m_body.virtual) {
                                s_body.virtual = true;
                            }
                            switch (String(v1.pttype).toLowerCase()) {
                                case "dos":
                                    break;
                                case "gpt":
                                    s_body.primary = true;
                                    break;
                            }
                            s_body.name = deepCopy(v2.name);
                            s_body.read_only = deepCopy(v2.ro);
                            s_body.removable_disk = deepCopy(v2.rm);
                            s_body.type = deepCopy(v2.type);
                            s_body.size = deepCopy(v2.size);
                            s_body.path = deepCopy(v2.path);
                            if (v2.fsavail) {
                                s_body.free = deepCopy(v2.fsavail);
                            } else {
                                s_body.free = 0;
                            }
                            if (v2.fsver) {
                                s_body.fileSystem = deepCopy(v2.fsver);
                            } else if (v2.fstype) {
                                s_body.fileSystem = deepCopy(v2.fstype);
                            }
                            s_body.volumeSerial = deepCopy(v2.uuid);
                            s_body.volumeName = deepCopy(v2.label);
                            if (v2.mountpoint !== null) {
                                if (String(v2.mountpoint).length === 1 && String(v2.mountpoint).toString() === "/") {
                                    s_body.system = true;
                                    m_body.system = true;
                                    s_body.mount = deepCopy(v2.mountpoint);
                                } else {
                                    s_body.mount = deepCopy(v2.mountpoint);
                                    s_body.system = false;
                                }
                            }
                            m_body.partition.push(s_body);
                        });
                    }
                    if (v1.mountpoint !== null) {
                        if (String(v1.mountpoint).length === 1 && String(v1.mountpoint).toString() === "/") {
                            m_body.system = true;
                            m_body.mount = deepCopy(v1.mountpoint);
                        } else {
                            m_body.system = false;
                        }
                    }
                    StorageDeviceList.push(m_body);
                });
            } catch (e) {
                e.message = "";
            }
            break;
        case "win32":
            const DRIVE_Optical_Disk = 5;
            const DRIVE_Hard_Disk = 3;
            const DRIVE_Network_Disk = 4;
            const DRIVE_Virtual_Disk = 6;
            const DRIVE_Removable_Disk = 2;
            const current_Visual_Basic_Script = ps.join(__dirname, "ToolsCollection", "SystemProcess", "runtimeEnviron", "StorageDevice", "getStorageDevice.vbs");
            var exist_letter = [];
            var exist_Optical_Disk = [];
            var exist_Hard_Disk = [];
            var exist_Disk_Partition = [];
            var optical_disk_info1 = child_process.execSync(`cscript /NoLogo ${current_Visual_Basic_Script} Optical_Disk`).toString("utf8");
            var partition_info1 = child_process.execSync(`cscript /NoLogo ${current_Visual_Basic_Script} Disk_Partition`).toString("utf8");
            var hard_disk_info1 = child_process.execSync(`cscript /NoLogo ${current_Visual_Basic_Script} Hard_Disk`).toString("utf8");
            exist_Optical_Disk = String(optical_disk_info1).split(os.EOL);
            exist_Hard_Disk = String(hard_disk_info1).split(os.EOL);
            exist_Disk_Partition = String(partition_info1).split(os.EOL);
            win32_disk_letter.forEach(function (value) {
                try {
                    fs.statSync(`${value}:`);
                    var win32_letter_info = {
                        letter: "",
                        size: 0,
                        free: 0,
                        type: 0,
                        fileSystem: null,
                        VolumeSerialNumber: null,
                        VolumeName: null
                    };
                    var letter_info1 = child_process.execSync(`cscript /NoLogo ${current_Visual_Basic_Script} Letter ${value}:`).toString("utf8");
                    var letter_split = String(letter_info1).split(os.EOL);
                    EraseMatchArrayItems(letter_split, "");
                    win32_letter_info.letter = deepCopy(letter_split[0]);
                    win32_letter_info.type = parseInt(letter_split[1]);
                    if (String(letter_split[2]).toLowerCase().indexOf("null") > -1 || !letter_split[2]) {
                        win32_letter_info.size = 0;
                    } else {
                        win32_letter_info.size = parseInt(deepCopy(letter_split[2]));
                    }
                    if (String(letter_split[3]).toLowerCase().indexOf("null") > -1 || !letter_split[3]) {
                        win32_letter_info.free = 0;
                    } else {
                        win32_letter_info.free = parseInt(deepCopy(letter_split[3]));
                    }
                    if (String(letter_split[4]).toLowerCase().indexOf("null") > -1 || !letter_split[4]) {
                        win32_letter_info.fileSystem = null;
                    } else {
                        win32_letter_info.fileSystem = String(deepCopy(letter_split[4])).toString();
                    }
                    if (String(letter_split[5]).toLowerCase().indexOf("null") > -1 || !letter_split[5]) {
                        win32_letter_info.VolumeSerialNumber = null;
                    } else {
                        win32_letter_info.VolumeSerialNumber = String(deepCopy(letter_split[5])).toString();
                    }
                    if (String(letter_split[6]).toLowerCase().indexOf("null") > -1 || !letter_split[6]) {
                        win32_letter_info.VolumeName = null;
                    } else {
                        win32_letter_info.VolumeName = String(deepCopy(letter_split[6])).toString();
                    }
                    exist_letter.push(win32_letter_info);
                } catch (e) {
                    e.message = "";
                }
            });
            EraseMatchArrayItems(exist_Optical_Disk, "");
            EraseMatchArrayItems(exist_Hard_Disk, "");
            EraseMatchArrayItems(exist_Disk_Partition, "");
            exist_Optical_Disk.forEach(function (value, index, array) {
                if (value === "-") {
                    var odd_info = m_info();
                    odd_info.model = deepCopy(array[index + 1]);
                    odd_info.mount = deepCopy(array[index + 2]);
                    odd_info.path = deepCopy(array[index + 2]);
                    if (String(array[index + 3]).toLowerCase().indexOf("null") > -1) {
                        odd_info.size = null;
                    } else {
                        odd_info.size = parseInt(deepCopy(array[index + 3]));
                    }
                    odd_info.serial_Number = deepCopy(array[index + 4]);
                    try {
                        exist_letter.forEach(function (v1, i1) {
                            if (v1.type === DRIVE_Optical_Disk && size_comp(odd_info.size, v1.size)) {
                                odd_info.partition.push(deepCopy(v1));
                                throw {pos: i1}
                            }
                        });
                    } catch (e) {
                        exist_letter.splice(e.pos, 1);
                    }
                    odd_info.removable_disk = true;
                    odd_info.type = "Optical Disk";
                    StorageDeviceList.push(deepCopy(odd_info));
                }
            });
            exist_Hard_Disk.forEach(function (value, index, array) {
                if (value === "-") {
                    var hdd_info = m_info();
                    hdd_info.path = deepCopy(array[index + 1]);
                    hdd_info.index = parseInt(deepCopy(array[index + 2]));
                    hdd_info.size = parseInt(deepCopy(array[index + 3]));
                    hdd_info.interfaces = deepCopy(array[index + 4]);
                    hdd_info.model = deepCopy(array[index + 5]);
                    hdd_info.serial_Number = deepCopy(array[index + 6]);
                    exist_Disk_Partition.forEach(function (v1, i1, a1) {
                        if (v1 === "-") {
                            if (hdd_info.index === parseInt(deepCopy(a1[i1 + 1]))) {
                                var partition_info = s_info();
                                partition_info.index = parseInt(deepCopy(a1[i1 + 2]));
                                partition_info.size = parseInt(deepCopy(a1[i1 + 3]));
                                if (String(deepCopy(a1[i1 + 4])).toString() === "-1") {
                                    partition_info.primary = true;
                                } else {
                                    partition_info.primary = false;
                                }
                                try {
                                    exist_letter.forEach(function (v2, i2, a2) {
                                        if (v2.type === DRIVE_Hard_Disk && size_comp(partition_info.size, v2.size)) {
                                            partition_info.path = deepCopy(v2.letter);
                                            partition_info.free = deepCopy(v2.free);
                                            partition_info.mount = deepCopy(v2.letter);
                                            partition_info.volumeName = deepCopy(v2.VolumeName);
                                            partition_info.name = deepCopy(v2.VolumeName);
                                            if (String(node_process.env.SystemDrive).indexOf(v2.letter) >= 0) {
                                                partition_info.system = true;
                                                hdd_info.system = true;
                                            }
                                            partition_info.type = "Hard Disk";
                                            throw {pos: i2}
                                        }
                                    });
                                } catch (e) {
                                    exist_letter.splice(e.pos, 1);
                                }
                                hdd_info.partition.push(deepCopy(partition_info));
                            }
                        }
                    });
                    StorageDeviceList.push(deepCopy(hdd_info));
                }
            });
            if (exist_letter.length > 0) {
                while (true) {
                    var clears = false;
                    try {
                        exist_letter.forEach(function (value, index, array) {
                            var sa = s_info();
                            sa.size = deepCopy(value.size);
                            sa.free = deepCopy(value.free);
                            sa.name = deepCopy(value.VolumeName);
                            sa.volumeName = deepCopy(value.VolumeName);
                            sa.volumeSerial = deepCopy(value.VolumeSerialNumber);
                            sa.fileSystem = deepCopy(value.fileSystem);
                            sa.path = deepCopy(value.letter);
                            sa.mount = deepCopy(value.letter);
                            switch (value.type) {
                                case DRIVE_Removable_Disk:
                                    sa.type = "Removable Disk";
                                    sa.removable_disk = true;
                                    break;
                                case DRIVE_Virtual_Disk:
                                    sa.type = "Virtual Disk";
                                    break;
                                case DRIVE_Optical_Disk:
                                    sa.type = "Optical Disk";
                                    break;
                                case DRIVE_Hard_Disk:
                                    sa.type = "Hard Disk";
                                    break;
                                case DRIVE_Network_Disk:
                                    sa.type = "Network Disk";
                                    break;
                            }
                            StorageDeviceList.push(deepCopy(sa));
                            throw {pos: index};
                        });
                        clears = true;
                    } catch (e) {
                        exist_letter.splice(e.pos, 1);
                    }
                    if (clears) {
                        break;
                    }
                }
            }
            break;
    }

    return StorageDeviceList;
}

module.exports = {getAllStorageDevice}